package com.vert.db.impl;

import com.vert.annotations.Service;
import com.vert.c3p0.C3P0DataSource;
import com.vert.db.SqlBuilder;
import com.vert.db.TableService;
import com.vert.db.model.DBModel;
import com.vert.db.model.IPage;
import com.vert.db.utils.SqlUtils;
import com.vert.utils.DataSourceUtils;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @Classname TableServiceImpl
 * @Description TODO
 * @Date 2022/5/29 20:37
 * @Created by XiongXiong
 * @Author: X.I.O
 */
@Service
public class TableServiceImpl implements TableService {

      @Override
      public <T> T getOneById(Object id, Class<?> cls) {
          DBModel dbModel=getDBModel(cls);
          String byIdSql=dbModel.getByIdSql(id);
          return this.selectMapObj(byIdSql,dbModel);
      }

      @Override
      public <T> T updateOneById(T t, Class<?> cls) {
        DBModel dbModel = getDBModel(cls);
        String updateSql=dbModel.updateSql(t);
        this.updateSql(updateSql);
        return t;
      }

      @Override
      public <T> T saveOne(T t, Class<?> cls) {
        DBModel dbModel = getDBModel(cls);
        String sqlSql=dbModel.getSaveSQL(t);
        this.insert(sqlSql);
        String sql=String.format("select  LAST_INSERT_ID() from %s limit 1",dbModel.getTableName());
        int id=this.selectCount(sql);
        System.out.println(id);
        dbModel.setFieldValue(t,id,dbModel.getId());
        return t;
      }

      @Override
      public SqlBuilder getSqlBuilder(Class<?> cls) {
          DBModel dbModel=getDBModel(cls);
          return dbModel.getSqlBuilder();
      }

      @Override
      public <T> T selectOne(SqlBuilder sqlBuilder,Class<?> cls) {
          DBModel dbModel = getDBModel(cls);
          String sql=sqlBuilder.getSql();
        System.out.println(sql);
          return this.selectMapObj(sql,dbModel);
      }

      @Override
      public <T> List<T> selectList(SqlBuilder sqlBuilder,Class< ? > cls) {
        DBModel dbModel = getDBModel(cls);
        String sql=sqlBuilder.getSql();
        return this.selectList(sql,dbModel);
      }

      @Override
      public <T> IPage<T> getPage(SqlBuilder sqlBuilder,Class< ? > cls) {
        DBModel dbModel = getDBModel(cls);
        String page = sqlBuilder.getPage();
        String count=sqlBuilder.getCountSql();
        System.out.println(page);
        System.out.println(count);
        List<T> list=this.selectList(page,dbModel);
        int totalCount=this.selectCount(count);
        return new IPage<>(totalCount,list);
      }

      @Override
      public <T> List<T> getList(Class<?> cls) {
          DBModel dbModel=getDBModel(cls);
          String sql=dbModel.getSelectAllList();
          return this.selectList(sql,dbModel);
      }




      public DBModel getDBModel(Class< ? > cls) {
          return SqlUtils.getDBModelByClass(cls);
      }

      private boolean updateSql(String sql){
        Connection connection=null;
        try {
            connection=getConnection();
            sqlExecute(sql,connection);
        }catch (Exception e) {
          e.printStackTrace();
        }finally {
          closeConnection(connection);
        }
        return true;
      }


      private <T> List<T> selectList(String sql,DBModel dbModel){
          Connection connection=getConnection();
          ResultSet rs = this.sqlExecuteQuery(sql,connection);
          if(rs==null){
              return new ArrayList<>();
          }
          try {
            List<T> tList=new ArrayList<>();
            int n=0;
            String[] fields = this.getFeildList(rs);
            while (rs.next()){
                T t=(T) dbModel.getObject();
                for(int i = 0; i < fields.length; ++i) {
                  String dbField = fields[i];
                  Object value = rs.getObject(dbField);
                  dbModel.setFieldValueByDBField(t,value,dbField);
                }
                tList.add(t);
            }
            return tList;
          }catch (Exception e) {
              e.printStackTrace();
          }finally {
              closeConnection(connection);
          }
          return null;
      }


      private  <T> T selectMapObj(String sql,DBModel dbModel) {
          Connection connection=getConnection();
          ResultSet resultSet = this.sqlExecuteQuery(sql,connection);
          if (resultSet == null) {
              return (T)dbModel.getObject();
          }
          T t=(T)dbModel.getObject();
          String[] fields = this.getFeildList(resultSet);
          try {
            if (resultSet.next()) {
              for(int i = 0; i < fields.length; ++i) {
                  String dbField = fields[i];
                  Object value = resultSet.getObject(dbField);
                  dbModel.setFieldValueByDBField(t,value,dbField);
              }
              return t;
            }
          } catch (Exception var11) {
            var11.printStackTrace();
          }finally {
            closeConnection(connection);
          }
          return null;
      }

      public int selectCount(String sql){
          Connection connection = getConnection();
          ResultSet resultSet = this.sqlExecuteQuery(sql,connection);
          try {
            resultSet.next();
            int count = resultSet.getInt(1);
            return count;
          }catch (SQLException e){
            e.printStackTrace();
          }finally {
              closeConnection(connection);
          }
          return 0;
      }

      private boolean insert(String sql){
          Connection conn = null;
          PreparedStatement sta=null;
          try {
            conn=getConnection();
            sta=conn.prepareStatement(sql);
            boolean b= sta.execute();
            return b;
          }catch (Exception var12) {
            var12.printStackTrace();
          }finally {
              closeConnection(conn);
          }
          return false;
      }

      private String[] getFeildList(ResultSet rs) {
        try {
          ResultSetMetaData rsmd = rs.getMetaData();
          String[] lie = new String[rsmd.getColumnCount()];
          for(int i = 1; i < rsmd.getColumnCount() + 1; ++i) {
            lie[i - 1] = rsmd.getColumnName(i);
          }
          return lie;
        } catch (Exception var5) {
          var5.printStackTrace();
          return new String[0];
        }
      }

      private Connection getConnection(){
        C3P0DataSource c3P0DataSource= DataSourceUtils.getC3P0DataSource();
        return c3P0DataSource.getConnection();
      }

      private void closeConnection(Connection connection){
        C3P0DataSource c3P0DataSource= DataSourceUtils.getC3P0DataSource();
        c3P0DataSource.clonse(connection);
        connection=null;
      }

    private ResultSet sqlExecuteQuery(String sql,Connection conn) {
      Statement stmt = null;
      ResultSet rs = null;
      try {
        if (conn == null) {
            return null;
        } else {
            stmt = conn.createStatement();
            rs = stmt.executeQuery(sql);
            return rs;
        }
      } catch (Exception var5) {
        var5.printStackTrace();
        return rs;
      }
    }

    private boolean sqlExecute(String sql,Connection conn) {
      boolean flag = false;
      Statement stmt = null;
      try {
        stmt = conn.createStatement();
        flag = stmt.execute(sql);
        return flag;
      } catch (Exception var8) {
        var8.printStackTrace();
      }
      return flag;
    }

}
